package org.hako.recite.word.test.impl.gui.swing;

import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.hako.recite.word.gui.swing.AbstractReciteWordFrame;
import org.hako.recite.word.input.RomaToNihongoConverter;
import org.hako.recite.word.test.WordTestResource;
import org.hako.recite.word.test.impl.gui.NullWordTestBehavior;
import org.hako.recite.word.test.impl.gui.WordTestBehavior;

/**
 * Frame of word test.
 * 
 * @since 0.4.2
 * @author <a href="mailto:xnnyygn@gmail.com">xnnyygn</a>
 */
public class WordTestFrame extends AbstractReciteWordFrame {

	private JLabel lbQuestion;
	private JTextField tfUserAnswer;
	private JLabel lbHint;
	private WordTestResource resource;
	private int currentIndex;
	private int questionCount;
	private boolean showingHint;
	private JLabel lbQuestionCounter;
	private WordTestBehavior behavior;
	private RomaToNihongoConverter romaConverter;
	private JCheckBox cbEnableRomaConvert;
	private JTextField tfRomaInput;

	/**
	 * Create
	 */
	public WordTestFrame() {
		this(new NullWordTestBehavior());
	}

	/**
	 * Create
	 * 
	 * @param behavior
	 */
	public WordTestFrame(WordTestBehavior behavior) {
		super("Word Test");
		this.behavior = behavior;
		JPanel mainPanel = new JPanel(new GridLayout(6, 1, 0, 5));
		mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
		addComponentsToPane(mainPanel);
		frame.add(mainPanel);
		frame.setResizable(false);
		frame.pack();
		frame.setSize(400, (int) frame.getSize().getHeight());

		// center in the monitor
		centerInScreen();
	}

	/**
	 * Add component to pane.
	 * 
	 * @param container
	 */
	private void addComponentsToPane(Container container) {
		lbQuestionCounter = new JLabel("Question counter");
		container.add(lbQuestionCounter);
		lbQuestion = new JLabel("Question");
		container.add(lbQuestion);

		tfUserAnswer = new JTextField();
		tfUserAnswer.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				onUserAnswerEnter();
			}
		});
		container.add(tfUserAnswer);
		cbEnableRomaConvert = new JCheckBox("Enable Roma Convert");
		cbEnableRomaConvert.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				boolean enabled = cbEnableRomaConvert.isSelected();
				tfRomaInput.setEnabled(enabled);
				if (enabled) {
					if (romaConverter == null) {
						romaConverter = new RomaToNihongoConverter();
					}
				}
			}
		});
		container.add(cbEnableRomaConvert);
		tfRomaInput = new JTextField();
		tfRomaInput.setEnabled(false);
		tfRomaInput.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				onUserAnswerEnter();
			}
		});
		tfRomaInput.addKeyListener(new KeyAdapter() {

			@Override
			public void keyReleased(KeyEvent e) {
				if (!cbEnableRomaConvert.isSelected()) {
					return;
				}
				String source = tfRomaInput.getText().trim();
				if (source.length() == 0) {
					tfUserAnswer.setText("");
				} else {
					tfUserAnswer.setText(romaConverter.convert(source));
				}
			}

		});
		container.add(tfRomaInput);
		lbHint = new JLabel("Hint");
		container.add(lbHint);
	}

	/**
	 * Show window and start test.
	 * 
	 * @param resource
	 * @see JFrame#setVisible(boolean)
	 */
	public void show(WordTestResource resource) {
		this.resource = resource;
		currentIndex = 0;
		questionCount = resource.getQuestionCount();
		showingHint = false;
		showQuestion(0);
		frame.setVisible(true);
	}

	/**
	 * Show next question.
	 */
	private void showNextQuestion() {
		currentIndex++;
		if (currentIndex >= questionCount) {
			showResult();
			behavior.finishTest();
		} else {
			showQuestion(currentIndex);
		}
	}

	/**
	 * Show question.
	 * 
	 * @param index
	 */
	private void showQuestion(int index) {
		StringBuilder builder = new StringBuilder();
		builder.append("Question ");
		builder.append(index + 1);
		builder.append('/');
		builder.append(questionCount);
		lbQuestionCounter.setText(builder.toString());
		lbQuestion.setText(resource.getQuestion(index));
		tfUserAnswer.setText("");
		if (cbEnableRomaConvert.isSelected()) {
			tfRomaInput.setText("");
		}
		lbHint.setText("");
	}

	/**
	 * Show test result.
	 */
	private void showResult() {
		JOptionPane.showMessageDialog(frame,
				resource.generateWrongWordsReport());
	}

	/**
	 * When user press {@code Enter} in field "user answer", this method will be
	 * invoked.
	 */
	private void onUserAnswerEnter() {
		if (showingHint) {
			showingHint = false;
			showNextQuestion();
			return;
		}

		String userAnswer = tfUserAnswer.getText().trim();

		// check if is blank
		if (userAnswer.length() == 0) {
			return;
		}
		String correctAnswer = resource.getAnswer(currentIndex);
		if (!correctAnswer.equals(userAnswer)) {
			resource.addWrong(currentIndex);

			// show hint
			showingHint = true;
			lbHint.setText(correctAnswer);
		} else {

			// right
			showNextQuestion();
		}
	}
}
